#include "stdafx.h"

/*************************
* The constructor & destructor for Sheet
***/
Sheet::Sheet()
{
	// Build the head node
	pcRowHead = new RowHeader();
	pcColumnHead = new ColHeader();
}

Sheet::~Sheet()
{
	// Free the memories
	delete pcRowHead;
	delete pcColumnHead;
}

bool Sheet::ModifyCellContent(ROW_NUM iRow, COL_NUM iColumn, const wstring& strContent, MemState& mem, bool remove)
{
	Cell cell(0,0,0,0);
	cell.strContent = strContent;
	return modifyCell(iRow, iColumn, cell, CELL_MF_CONTENT, mem, remove);
}

/*****************************
 * Modify the content of the Cell at (iColumn,iRow)
 * mem returns the state before modifying
 ***/
bool Sheet::modifyCell(ROW_NUM iRow, COL_NUM iColumn, const Cell& objCell,ModifiedField field,  MemState& mem, bool remove)
{
	if (iRow > ROW_MAX || iColumn > COL_MAX)
	{
		return false;
	}
	//(1) to find out whether cell (iRow, iColumn) exists	
	//(2.1) if exists, modify the content
	//(2.2) if not, create the cell and save the content

	Cell* pcCell = FindCell(iRow, iColumn);
	if(pcCell != 0 && objCell.strContent == TEXT(""))
	{
		// if the content is modified to null
		// and the style is default
		// then remove this cell.

		// or indicates to remove this cell explicitly
		mem = pcCell->GetState();
		if (remove || pcCell->IsDefaultStyle())
		{
			mem = pcCell->GetState(CELL_MF_ALL);
			RemoveCell(iRow, iColumn);
		}
		else
			pcCell->strContent = objCell.strContent;
		return true;
	}
	else if(pcCell == 0 && objCell.strContent== TEXT(""))
	{
		// if the cell doesn't exist, and no content is entering
		// then just return
		return false;
	}
	else if(pcCell == 0)	
	{
		pcCell = AddCell(iRow,iColumn);
	}
	mem = pcCell->GetState();
	if ((field & CELL_MF_CONTENT) !=0 )
		pcCell->strContent = objCell.strContent;
	return true;
}

/*****************************
* Find the Cell at (iColumn,iRow)
* If the cell exists, return the pointer to that.
* Otherwise, return 0.
***/
Cell* Sheet::FindCell(ROW_NUM iRow, COL_NUM iColumn)
{
	if (iRow > ROW_MAX || iColumn > COL_MAX)
	{
		return 0;
	}
	ROW_NUM iCurrentRow=0;
	COL_NUM iCurrentColumn=0;

	RowHeader* pcCurrentRowHeader = pcRowHead;
	while (pcCurrentRowHeader->pCellBelow)
	{
		pcCurrentRowHeader = (RowHeader*)(pcCurrentRowHeader->pCellBelow);
		iCurrentRow = pcCurrentRowHeader->iRowNum;
		//iCurrentRow += pcCurrentRowHeader->iDistanceAbove;

		if (iCurrentRow < iRow)
			continue;
		else if (iCurrentRow == iRow)
		{
			// the row of 'iRow' is found, now find col
			// at first, cell pointer points to the Header of 'iRow'
			CellNode* pcCurrentCell = pcCurrentRowHeader;
			while (pcCurrentCell->pCellRight)
			{
				pcCurrentCell = pcCurrentCell->pCellRight;
				iCurrentColumn = ((Cell*)pcCurrentCell)->GetColumnNumber();
				//iCurrentColumn += pcCurrentCell->iDistanceLeft;

				if (iCurrentColumn < iColumn)
					continue;
				else if (iCurrentColumn == iColumn)
				{
					// the cell is found
					return (Cell*)pcCurrentCell;
				}
				// cannot find the cell at col of 'iColumn'
				return 0;
			}
			// do not have any Cell at this Row
			return 0;
		}
		// the row of 'iRow' is not created
		return 0;
	}
	return 0;	// do not have any row
}

/****************************
* Add a Cell at (iColumn, iRow).
* Return the pointer to the cell just added.
***/
Cell* Sheet::AddCell(ROW_NUM iRow, COL_NUM iColumn)
{
	// If the iRow/iColumn exists, AddRowHeaderNode/AddColHeaderNode will just return the pointer
	RowHeader* pRowHeader = AddRowHeaderNode(iRow);
	ColHeader* pColHeader = AddColHeaderNode(iColumn);

	CellNode* pRowCursor = pRowHeader;
	CellNode* pColCursor = pColHeader;

	while (pRowCursor->pCellRight!=0)
	{
		int currentColumn = ((Cell*)pRowCursor->pCellRight)->GetColumnNumber();
		if (currentColumn < iColumn)
		{
			pRowCursor = pRowCursor->pCellRight;
			continue;
		}
		else if (currentColumn == iColumn)
		{
			return ((Cell*)pRowCursor->pCellRight);
		}
		else
		{
			break;
		}
	}
	//Now that the pRowCursor has pointed to the Cell just at left of the (iRow,iColumn)
	
	//And we also have to find the pColCursor by the same method
	while (pColCursor->pCellBelow!=0)
	{
		int currentRow = ((Cell*)pColCursor->pCellBelow)->GetRowNumber();
		if (currentRow < iRow)
		{
			pColCursor = pColCursor->pCellBelow;
			continue;
		}
		else if (currentRow == iRow)
		{
			return ((Cell*)pColCursor->pCellBelow);
		}
		else
		{
			break;
		}
	}
	//Now that the pColCursor has pointed to the Cell just above the (iRow,iColumn)
	Cell* pNewCell = new Cell(pRowHeader, pColHeader, pColCursor->pCellBelow, pRowCursor->pCellRight);
	pRowCursor->pCellRight = pNewCell;
	pColCursor->pCellBelow = pNewCell;
	
	pRowHeader->CountIncrease();
	pColHeader->CountIncrease();
	return pNewCell;
}

void Sheet::RemoveCell(ROW_NUM iRow, COL_NUM iColumn)
{
	// If the iRow/iColumn exists, AddRowHeaderNode/AddColHeaderNode will just return the pointer
	RowHeader* pRowHeader = AddRowHeaderNode(iRow);
	ColHeader* pColHeader = AddColHeaderNode(iColumn);
	if (pRowHeader == 0 || pColHeader == 0)
	{
		return;
	}

	CellNode* pRowCursor = pRowHeader;
	CellNode* pColCursor = pColHeader;

	while (pRowCursor->pCellRight!=0)
	{
		int currentColumn = ((Cell*)pRowCursor->pCellRight)->GetColumnNumber();
		if (currentColumn < iColumn)
		{
			pRowCursor = pRowCursor->pCellRight;
			continue;
		}
		else if (currentColumn == iColumn)
		{
			break;
		}
		else
		{
			return;
		}
	}
	//Now that the pRowCursor has pointed to the Cell just at left of the (iRow,iColumn)

	//And we also have to find the pColCursor by the same method
	while (pColCursor->pCellBelow!=0)
	{
		int currentRow = ((Cell*)pColCursor->pCellBelow)->GetRowNumber();
		if (currentRow < iRow)
		{
			pColCursor = pColCursor->pCellBelow;
			continue;
		}
		else if (currentRow == iRow)
		{
			break;
		}
		else
		{
			return;
		}
	}
	//Now that the pColCursor has pointed to the Cell just above the (iRow,iColumn)
	
	deleteCell(pRowCursor, pColCursor);

	pRowHeader->CountDecrease();
	pColHeader->CountDecrease();

	if (pRowHeader->Empty())
	{
		deleteRowHeader(pRowHeader);
	}
	if (pColHeader->Empty())
	{
		deleteColHeader(pColHeader);
	}
	return;
}

/****************************
* Add a Row with row number of iRow.
* Return the pointer to the RowHeader just added.
* If insert == true, rows below will increase the number
***/
RowHeader* Sheet::AddRowHeaderNode(ROW_NUM iRow, bool insert)
{
	if (iRow > ROW_MAX)
	{
		return 0;
	}
	RowHeader* pcCurrentHeader = pcRowHead;
	while(pcCurrentHeader->pCellBelow !=0)
	{
		if (((RowHeader*)pcCurrentHeader->pCellBelow)->iRowNum < iRow )
		{
			// The next node < iRow, find for next
			pcCurrentHeader = (RowHeader*)pcCurrentHeader->pCellBelow;
			continue;
		}
		else if(((RowHeader*)pcCurrentHeader->pCellBelow)->iRowNum == iRow )
		{
			// The next node == iRow, return next node
			if (insert)
			{
				break;
			}
			return (RowHeader*)pcCurrentHeader->pCellBelow;
		}
		else
		{
			// The next node > iRow, then iRow should be inserted
			break;
		}
	}
	// There's no any RowHeader node currently, then Add a New One
	RowHeader* pNewHeader = new RowHeader();
	pNewHeader->iRowNum = iRow;

	pNewHeader->pCellBelow = pcCurrentHeader->pCellBelow;
	pcCurrentHeader->pCellBelow = pNewHeader;

	if (pNewHeader->pCellBelow!=0)
	{
		((RowHeader*)(pNewHeader->pCellBelow))->pRowAbove = pNewHeader;
	}
	pNewHeader->pRowAbove = pcCurrentHeader;
	return pNewHeader;
}

RowHeader* Sheet::AddRow(ROW_NUM iRow)
{
	RowHeader* pNewHeader = AddRowHeaderNode(iRow, true);
	// increase the ROW_NUM below
	modifyRowNum((RowHeader*)pNewHeader->pCellBelow);
	return pNewHeader;

}

ColHeader* Sheet::AddColumn(COL_NUM iColumn)
{
	ColHeader* pNewHeader = AddColHeaderNode(iColumn, true);
	// increase the COL_NUM on the right
	modifyColNum((ColHeader*)pNewHeader->pCellRight);

	return pNewHeader;
}

/****************************
* Add a Column with column number of iColumn.
* Return the pointer to the ColHeader just added.
***/
ColHeader* Sheet::AddColHeaderNode(COL_NUM iColumn, bool insert)
{
	if (iColumn > COL_MAX)
	{
		return 0;
	}
	ColHeader* pcCurrentHeader = pcColumnHead;
	while(pcCurrentHeader->pCellRight !=0)
	{
		if (((ColHeader*)pcCurrentHeader->pCellRight)->iColNum < iColumn )
		{
			// The next node < iColumn, find for next
			pcCurrentHeader = (ColHeader*)pcCurrentHeader->pCellRight;
			continue;
		}
		else if(((ColHeader*)pcCurrentHeader->pCellRight)->iColNum == iColumn )
		{
			// The next node == iColumn, return next node
			if (insert)
			{
				break;
			}
			return (ColHeader*)pcCurrentHeader->pCellRight;
		}		
		else
		{
			// The next node > iColumn, then iColumn should be inserted
			break;
		}
	}
	// There's no any ColHeader node currently, then Add a New One
	ColHeader* pNewHeader = new ColHeader();
	pNewHeader->iColNum = iColumn;

	pNewHeader->pCellRight = pcCurrentHeader->pCellRight;
	pcCurrentHeader->pCellRight = pNewHeader;

	if (pNewHeader->pCellRight!=0)
	{
		((ColHeader*)(pNewHeader->pCellRight))->pColLeft = pNewHeader;
	}
	pNewHeader->pColLeft = pcCurrentHeader;
	return pNewHeader;
}

/******************************************
 * Remove the Row at iRow
 ***/
void Sheet::RemoveRow(ROW_NUM iRow)
{
	RowHeader* pRowHeader = AddRowHeaderNode(iRow);
	CellNode* pCellNode = pRowHeader;
	RowHeader* pNextRowHeader = (RowHeader*)(pRowHeader->pCellBelow);
	if (pRowHeader->Empty())
	{		
		deleteRowHeader(pRowHeader);
		modifyRowNum(pNextRowHeader, false);
		return;
	}
	while (pCellNode->pCellRight!=0)
	{
		RemoveCell(iRow, ((Cell*)(pCellNode->pCellRight))->GetColumnNumber());
		if (pRowHeader->GetCount() == 1)
		{
			RemoveCell(iRow, ((Cell*)(pCellNode->pCellRight))->GetColumnNumber());
			modifyRowNum(pNextRowHeader, false);
			return;
		}
	}
}

/******************************************
* Remove the Column at iCol
***/
void Sheet::RemoveColumn(COL_NUM iColumn)
{
	ColHeader* pColHeader = AddColHeaderNode(iColumn);
	CellNode* pCellNode = pColHeader;
	ColHeader* pNextColHeader = (ColHeader*)(pColHeader->pCellRight);
	if (pColHeader->Empty())
	{
		deleteColHeader(pColHeader);
		modifyColNum(pNextColHeader, false);
		return;
	}
	while (pCellNode->pCellBelow!=0)
	{
		RemoveCell(((Cell*)(pCellNode->pCellRight))->GetRowNumber(), iColumn);
		if (pColHeader->GetCount() == 1)
		{
			RemoveCell(((Cell*)(pCellNode->pCellRight))->GetRowNumber(), iColumn);
			modifyColNum(pNextColHeader, false);
			return;
		}
	}
}


/*******************************************
 * Increase/ Decrease the ROW_NUM from pRowStart
 ***/
void Sheet::modifyRowNum(RowHeader* pRowStart, bool IsIncrease)
{
	ROW_NUM seed = 1;
	if (!IsIncrease)
	{
		seed = -1;
	}
	while (pRowStart!=0)
	{
		pRowStart->iRowNum += seed;
		pRowStart = (RowHeader*)pRowStart->pCellBelow;
	}
	return;
}

/*******************************************
* Increase/ Decrease the COL_NUM from pColStart
***/
void Sheet::modifyColNum(ColHeader* pColStart, bool IsIncrease)
{
	COL_NUM seed = 1;
	if (!IsIncrease)
	{
		seed = -1;
	}
	while (pColStart!=0)
	{
		pColStart->iColNum += seed;
		pColStart = (ColHeader*)pColStart->pCellRight;
	}
	return;
}

/*****************************
 * Delete the RowHeader
 * Only used when no cell is in this row
 ***/
void Sheet::deleteRowHeader(ROW_NUM iRow)
{
	RowHeader* pcRowHeader = AddRowHeaderNode(iRow);
	deleteRowHeader(pcRowHeader);
}
/* over-ride */
void Sheet::deleteRowHeader(RowHeader* pcRowHeader)
{
	pcRowHeader->pRowAbove->pCellBelow = pcRowHeader->pCellBelow;
	if (pcRowHeader->pCellBelow!=0)
	{
		((RowHeader*)(pcRowHeader->pCellBelow))->pRowAbove = pcRowHeader->pRowAbove;
	}
	delete pcRowHeader;
}

/*****************************
* Delete the ColHeader
* Only used when no cell is in this Column
***/
void Sheet::deleteColHeader(COL_NUM iCol)
{
	ColHeader* pcColHeader  = AddColHeaderNode(iCol);
	deleteColHeader(pcColHeader);
}
/* over-ride */
void Sheet::deleteColHeader(ColHeader* pcColHeader)
{
	pcColHeader->pColLeft->pCellRight = pcColHeader->pCellRight;
	if (pcColHeader->pCellRight!=0)
	{
		((ColHeader*)(pcColHeader->pCellRight))->pColLeft = pcColHeader->pColLeft;
	}
	delete pcColHeader;
}

void Sheet::deleteCell(CellNode* pLeftCell, CellNode* pAboveCell)
{
	Cell* pDel = (Cell*)(pLeftCell->pCellRight);
	pLeftCell->pCellRight = pDel->pCellRight;
	pAboveCell->pCellBelow = pDel->pCellBelow;
	delete pDel;
	pDel = 0;
}

// Return the Old value
int Sheet::SetRowHeight(ROW_NUM iRow, int Height)
{
	RowHeader* pRowHeader = AddRowHeaderNode(iRow);
	int oldHeight = pRowHeader->iRowHeight;
	pRowHeader->iRowHeight = Height;
	if (Height == CELL_DEFHEIGHT && pRowHeader->Empty())
	{
		deleteRowHeader(pRowHeader);
	}
	return oldHeight;
}

// Return the Old value
int Sheet::SetColWidth(COL_NUM iCol, int Width)
{
	ColHeader* pColHeader = AddColHeaderNode(iCol);
	int oldWidth = pColHeader->iColWidth;
	pColHeader->iColWidth = Width;
	if (Width == CELL_DEFWIDTH && pColHeader->Empty())
	{
		deleteColHeader(pColHeader);
	}
	return oldWidth;
}

void Sheet::OutPutRegion(ROW_NUM iRow_s, ROW_NUM iRow_e, COL_NUM iCol_s, COL_NUM iCol_e, wstring & buf, const wstring & RowSplit, const wstring & ColSplit, bool needQuote)
{
	RowHeader* pRow_s = AddRowHeaderNode(iRow_s);
	RowHeader* pCurrentRow = pRow_s;
	int currentRow = iRow_s, currentCol = iCol_s;
	do 
	{
		if (pCurrentRow->iRowNum > iRow_e)
		{
			break;
		}
		if (pCurrentRow->iRowNum > currentRow)
		{
			int dt = pCurrentRow->iRowNum - currentRow;
			while(dt!=0)
			{
				buf.append(RowSplit);
				dt--;
			}
			currentRow = pCurrentRow->iRowNum;
		}
		CellNode* pCurrent = pCurrentRow;
		while (pCurrent->pCellRight)
		{
			pCurrent = pCurrent->pCellRight;
			Cell* pCell = (Cell*)(pCurrent);
			if (pCell->GetColumnNumber() < iCol_s)
				continue;
			if (pCell->GetColumnNumber() > iCol_e)
			{
				break;
			}
			if (pCell->GetColumnNumber() > currentCol)
			{
				int dt = pCell->GetColumnNumber() - currentCol;
				while(dt!=0)
				{
					buf.append(ColSplit);
					dt--;
				}
				currentCol = pCell->GetColumnNumber();
			}
			if (pCell->GetColumnNumber() == currentCol)
			{
				if (needQuote)
					buf.append(TEXT("\""));

				if (needQuote)
				{
					// express " as ""
					wstring st(*(pCell->GetContent()));
					size_t pos = 0;
					pos = st.find(TEXT('\"'), pos);
					while(pos!= wstring::npos)
					{
						st.replace(pos,1, TEXT("\"\""));
						pos += 2;
						pos = st.find(TEXT('\"'), pos);
					}
					buf.append(st);
				}
				else
					{buf.append(*(pCell->GetContent()));}

				if (needQuote)
					buf.append(TEXT("\""));
				buf.append(ColSplit);
				currentCol++;
				continue;
			}
		}
		buf.append(RowSplit);
		pCurrentRow = (RowHeader*)(pCurrentRow->pCellBelow);
		currentCol = iCol_s;
		currentRow++;
	} while (pCurrentRow!=0);

	if (pRow_s->Empty())
		deleteRowHeader(pRow_s);
}